package com.aSemy.qotwReader.core;

import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.regex.Pattern;

import com.aSemy.qotwReader.core.parseInput.*;
import com.aSemy.qotwReader.core.parseInput.exceptions.*;
import com.aSemy.qotwReader.core.question.*;
import com.aSemy.qotwReader.core.types.*;
import com.aSemy.qotwReader.core.utils.*;

import net.htmlparser.jericho.*;


/**
 * 
 * @author Adam Semenenko
 */
public class Reader
{    
    /**
     * Main function.
     * Arguments specify which question(s) to download, output format, Calibre directory, etc
     */
    public static void main(String[] args)
    {
        try
        {
            ParseArguments parse = new ParseArguments(args);
            Reader r = new Reader(parse.getReader(), parse.getOutputEbook(), parse.getCalibreDirectory());
            
            DownloadAction action = parse.getDownload();
            
            if (action == DownloadAction.all)
            {
                System.out.println("Getting ebooks for all questions");
                r.downloadAllQuestions();
            }
            else if (action == DownloadAction.url)
            {
                System.out.println("Getting ebooks for question " + action.getUrl());
                r.downloadQuestion(action.getUrl());
            }
            else if (action == DownloadAction.latest)
            {
                System.out.println("Getting ebook for the most recently closed question.");
                r.downloadLatestQuestion();
            }
        }
        catch (UnknownCommandException e)
        {
            System.out.println("Unable to parse commands!");
            System.out.println("-\n" + e.getMessage() + "\n-");
        }
        catch (UnknownArgumentException e)
        {
            System.out.println("Unable to parse arguments!");
            System.out.println("-\n" + e.getMessage() + "\n-");
        }
        catch (MissingArgumentException e)
        {
            System.out.println("Unable to find arguments!");
            System.out.println("-\n" + e.getMessage() + "\n-");
        }
        catch (NotDirectoryException e)
        {
            System.out.println("Could not read directory for calibre install!");
            System.out.println("-\n" + e.getMessage() + "\n-");
        }
        finally
        {
            System.out.println("Exiting");
            System.exit(-1);
        }
    }
    
    /** The type of reader to calibrate the output ebook for. */
    final private ReaderType reader;
    /** The type of ebook that should be made. */
    final private EbookType ebook;
    /** Where Calibre is installed. */
    final private File calibreDir;
    
    
    /**
     * A reader holds the variables needed for downloading and converting questions.
     * 
     * The variables used in the constructor must be assigned in. To enforce this they are final.
     * 
     * @param reader The type of reader to calibrate the output ebook for.
     * @param ebook The type of ebook that should be made.
     * @param calibreDir Where Calibre is installed on this computer
     */
    public Reader(ReaderType reader, EbookType ebook, File calibreDir)
    {
        this.reader = reader;
        this.ebook = ebook;
        this.calibreDir = calibreDir;
    }
    
    /**
     * Given a valid URL the reader will download and convert that question.
     * @param url The question to download and convert.
     */
    public void downloadQuestion(URL url)
    {
        try
        {
            System.out.println("Downloading question from " + url.toString());
            new Question(url, reader, ebook, calibreDir);
            System.out.println("Finished downloading question " + url.toString());
        } catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    
    /**
     * The reader will gather the URL of all closed questions,
     * from <a href="http://www.b3ta.com/questions">b3ta questions</a> page,
     * using {@link #downloadQuestion(URL)}.
     */
    public void downloadAllQuestions()
    {
        ArrayList<URL> questionURLs = getFinishedQuestionUrls();
        
        //System.out.println("Gathered URLs");
        for (URL u : questionURLs)
            downloadQuestion(u);

        System.out.println("Finished downloading all questions.");
    }
    
    /**
     * The reader will find the most recently closed question, download it, and convert it.
     */
    public void downloadLatestQuestion()
    {
        ArrayList<URL> questionURLs = getFinishedQuestionUrls();
        
        URL latest = questionURLs.get(0);
        
        downloadQuestion(latest);
    }
    
    /**
     * Looks at the page listing all questions
     * (<a href="http://www.b3ta.com/questions">b3ta questions</a>) 
     * and downloads all closed questions.
     * 
     * This is a bit hacky and fragile. 
     * Since on the questions page all close questions are listed after the 
     * 'off topic' thread, all links after this thread are saved. Only links
     * that start "/questions/" are counted as being a question.
     * 
     * TODO This could break if the off topic thread is moved/deleted,
     * questions are saved with a different URL, 
     * other results use the URL pattern "/questions/"
     * etc.
     * 
     * @return A list of the URLs of all qotws that have been closed.
     */
    private ArrayList<URL> getFinishedQuestionUrls()
    {
        ArrayList<URL> questionURLs = new ArrayList<URL>();
        
        try
        {
            URL questionsURL = new URL("http://www.b3ta.com/questions/");
            Source questionsSource = new Source(questionsURL);
            questionsSource.fullSequentialParse();
            
            // want to get a list of all question urls.
            
            // Need to skip past the new questions and get to the old ones.
            // Old ones start past the off topic thread, so get to where that
            // starts and then look at all links past that.
            int endOfCurrentQuestions = 0;
            for (Element e : questionsSource.getAllElements())
            {
                String elementText = e.getTextExtractor().toString();
                
                if (elementText.equals("Off Topic"))
                {
                    endOfCurrentQuestions = e.getEnd();
                    break; //Found where old questions start
                }
            }
            
            
            for (Element e : questionsSource.getAllElements(HTMLElementName.A))
            {
                // Skip until we're where old questions start
                if (endOfCurrentQuestions > e.getBegin())
                    continue;
                
                // want the link values of this
                final String questionURL = e.getAttributeValue("href");
                if (questionURL != null)
                {                    
                    if (Pattern.matches("^/questions/.+/$", questionURL))
                    {
                        URL qUrl = new URL(Filenames.b3taAddress + questionURL);
                        questionURLs.add(qUrl);
                    }
                }
            }
            
        } catch (MalformedURLException e)
        {
            e.printStackTrace();
        } catch (IOException e)
        {
            e.printStackTrace();
        }
        
        return questionURLs;
    }
}
